home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / mail / pine3.96.tar.gz / pine3.96.tar / pine3.96 / pico / os_vms.c < prev    next >
C/C++ Source or Header  |  1996-05-30  |  33KB  |  1,525 lines

  1. #if     !defined(lint) && !defined(DOS)
  2. static char rcsid[] = "$Id: os_vms.c,v 1.19 1996/05/31 00:09:45 mikes Exp $";
  3. #endif
  4. /*
  5.  * Program:     Operating system dependent routines - VMS 5.n
  6.  *
  7.  *
  8.  * Yehavi Bourvine
  9.  * Hebrew University of Jeruselem
  10.  * +972-2-585684
  11.  * YEHAVI@vms.huji.ac.il
  12.  *
  13.  * Please address all bugs and comments to "pine-bugs@cac.washington.edu"
  14.  *
  15.  *
  16.  * Pine and Pico are registered trademarks of the University of Washington.
  17.  * No commercial use of these trademarks may be made without prior written
  18.  * permission of the University of Washington.
  19.  * 
  20.  * Pine, Pico, and Pilot software and its included text are Copyright
  21.  * 1989-1996 by the University of Washington.
  22.  * 
  23.  * The full text of our legal notices is contained in the file called
  24.  * CPYRIGHT, included with this distribution.
  25.  */
  26.  
  27. #include     <stdio.h>
  28. #include    <errno.h>
  29. #include    <setjmp.h>
  30. #include    <time.h>
  31. #include    "osdep.h"
  32. #include        "pico.h"
  33. #include    "estruct.h"
  34. #include        "edef.h"
  35. #include        "efunc.h"
  36. #ifdef __ALPHA
  37. #include    <fcntl.h>
  38. #endif
  39. #include    <file.h>
  40. #include    <types.h>
  41. #include    <time.h>
  42.  
  43. #include <iodef.h>
  44. #include <ttdef.h>
  45. #include <tt2def.h>
  46. #include <lib$routines.h>
  47. #include <descrip.h>
  48.  
  49. /* Output channel and buffers */
  50. static short    TerminalChan;
  51. #define    MAXBUF    1024        /* Save up to 1024 characters before sending them */
  52. unsigned char    OutputBuffer[MAXBUF + 1];
  53. int    OutputBufferCounter;
  54. int timeout = 0;
  55.  
  56. /* For setting and resting the PASTHRU flag: */
  57. struct    {
  58.     unsigned char    class, type;
  59.     unsigned short    width;
  60.     unsigned long    BasicChar,
  61.             ExtendChar;
  62.     } TerminalChar;
  63.  
  64.  
  65. #define    SIGTYPE    void
  66.  
  67. struct DESC {        /* String descriptor */
  68.     short    length, type;
  69.     char    *address;
  70.     } ;
  71.  
  72.     int      kbseq();
  73.     SIGTYPE  do_hup_signal();
  74.     SIGTYPE  rtfrmshell();
  75. #ifdef    TIOCGWINSZ
  76.     SIGTYPE  winch_handler();
  77. #endif
  78.  
  79.  
  80. /*
  81.  * for alt_editor arg[] building
  82.  */
  83. #define    MAXARGS    10
  84.  
  85. /*
  86.  * ttopen - this function is called once to set up the terminal device 
  87.  *          streams.  if called as pine composer, don't mess with
  88.  *          tty modes, but set signal handlers.
  89.  */
  90. ttopen()
  91. {
  92.     long    status;
  93.     struct DESC TerminalDesc;
  94.     char    TerminalName[] = "SYS$OUTPUT:";
  95.     int     row, col;
  96.  
  97.     TerminalDesc.address = TerminalName; TerminalDesc.type = 0;
  98.     TerminalDesc.length = strlen(TerminalName);
  99.  
  100.     status = sys$assign(&TerminalDesc, &TerminalChan, (int)(0), (int)(0));
  101.     if((status & 0x1) == 0) {
  102.         printf("Can't assign channel to terminal\n");
  103.         exit(status);
  104.     }
  105.  
  106.     signal(SIGHUP,  do_hup_signal);    /* deal with SIGHUP */
  107.     signal(SIGTERM, do_hup_signal);    /* deal with SIGTERM */
  108. #ifdef    SIGTSTP
  109.     signal(SIGTSTP, SIG_DFL);
  110. #endif
  111.  
  112. /* Some default values since we do not have TERMCAP: */
  113.     eolexist = FALSE;
  114.     revexist = TRUE;
  115.     delchar = FALSE;
  116.     inschar = FALSE;
  117.       scrollexist = TRUE;
  118.  
  119.     init_kpnames();
  120.  
  121.     OutputBufferCounter = 0;    /* Output buffer is empty */
  122.  
  123. /* Set the PASTHRU bit */
  124.     status = sys$qiow((int)(0), TerminalChan, (short)(IO$_SENSEMODE),
  125.             NULL, (int)(0), (int)(0),
  126.             &TerminalChar, sizeof(TerminalChar),
  127.             (int)(0), (int)(0), (int)(0), (int)(0));
  128.     if((status & 0x1) == 0) {
  129.         printf("Can't read for set terminal to /PASTHRU\n");
  130.         exit(status);
  131.     }
  132.  
  133.     TerminalChar.ExtendChar |= TT2$M_PASTHRU;
  134.     status = sys$qiow((int)(0), TerminalChan, (short)(IO$_SETMODE),
  135.             NULL, (int)(0), (int)(0),
  136.             &TerminalChar, sizeof(TerminalChar),
  137.             (int)(0), (int)(0), (int)(0), (int)(0));
  138.     if((status & 0x1) == 0) {
  139.         printf("Can't set terminal to /PASTHRU\n");
  140.         exit(status);
  141.     }
  142.  
  143.     ttgetwinsz(&row, &col);
  144.     term.t_nrow = row;
  145.     term.t_ncol = col;
  146.     return(1);
  147. }
  148.  
  149.  
  150. /*
  151.  * ttresize - recompute the screen dimensions if necessary, and then
  152.  *          adjust pico's internal buffers accordingly.
  153.  */
  154. int
  155. ttresize ()
  156. {
  157.     int row, col;
  158.  
  159.     ttgetwinsz(&row, &col);
  160.     resize_pico(row, col);
  161. }
  162.  
  163.  
  164. /*
  165.  * ttclose - this function gets called just before we go back home to 
  166.  *           the command interpreter.  If called as pine composer, don't
  167.  *           worry about modes, but set signals to default, pine will 
  168.  *           rewire things as needed.
  169.  */
  170. ttclose()
  171. {
  172.     int    status;
  173.  
  174.     ttflush();
  175.  
  176. /* Clear the PASTHRU flag */
  177.     TerminalChar.ExtendChar &= ~TT2$M_PASTHRU;
  178.     status = sys$qiow((int)(0), TerminalChan, (short)(IO$_SETMODE),
  179.             NULL, (int)(0), (int)(0),
  180.             &TerminalChar, sizeof(TerminalChar),
  181.             (int)(0), (int)(0), (int)(0), (int)(0));
  182.     if((status & 0x1) == 0) {
  183.         printf("Can't set terminal to /NOPASTHRU\n");
  184.         exit(status);
  185.     }
  186.     sys$dassgn(TerminalChan);
  187.  
  188.     return(1);
  189. }
  190.  
  191.  
  192. /*
  193.  * ttspeed - return TRUE if tty line speed < 9600 else return FALSE
  194.  */
  195. ttisslow()
  196. {
  197.     return(TRUE);
  198. }
  199.  
  200.  
  201. /*
  202.  * ttgetwinsz - set global rows and columns values and return
  203.  */
  204. ttgetwinsz(row, col)
  205.      int *row, *col;
  206. {
  207. #define TT_STRING_SIZE 20
  208.        char string[TT_STRING_SIZE] ;   /* string for holding tt:'s dev name */
  209.        int rows, cols ;                 /* row / column vars */
  210.        unsigned long status ;          /* status return var */
  211.        unsigned long terminal_item = 797 ; /* JPI$_TERMINAL */
  212.        unsigned long tt_page_item = 170 ;  /* DVI$_TT_PAGE */
  213.        unsigned long devbufsz_item = 8 ;   /* DVI$_DEVBUFSIZ */
  214.        struct dsc$descriptor_vs tt_sdesc =
  215.                                {TT_STRING_SIZE,/* max string size */
  216.                                DSC$K_DTYPE_VT, /* descriptor type */
  217.                                DSC$K_CLASS_VS, /* descriptor class = var str */
  218.                                string} ;       /* pointer to var string */
  219.  
  220.  
  221. /* Set the defaults */
  222.        *row = NROW - 1;
  223.        *col = NCOL;
  224.  
  225.                /* Get our terminal's device name */
  226.        status = lib$getjpi(&terminal_item,NULL,NULL,NULL,&tt_sdesc,NULL) ;
  227.        if ((status&1) == 1)
  228.           {
  229.                /* Get our terminal's page size */
  230.           status = lib$getdvi(&tt_page_item,NULL,&tt_sdesc,&rows,NULL,NULL) ;
  231.                /* Get our terminal's page width */
  232.       if((status & 0x1) == 1) {
  233.               status = lib$getdvi(&devbufsz_item,NULL,&tt_sdesc,&cols,NULL,NULL) ;
  234.         if((status & 0x1) == 1) {
  235.                    /* Set the globals for rows and columns */
  236.                   *row = rows-1 ;
  237.                   *col = cols ;
  238.             }
  239.         }
  240.           }
  241.        else
  242.           printf("Can't find process's terminal -- using defaults.\n") ;
  243. }
  244.  
  245. /*
  246.  | Physically write a string to the terminal.
  247.  */
  248. write_terminal(string, size)
  249. char    *string;
  250. int    size;
  251. {
  252.     long    status;
  253.     short    iosb[4];
  254.  
  255.     status = sys$qiow((int)(0), TerminalChan, (short)(IO$_WRITEVBLK),
  256.             iosb, (int)(0), (int)(0),
  257.             string, size, (int)(0), (int)(0), (int)(0), (int)(0));
  258.     if(((status & 0x1) == 0) || ((iosb[0] & 0x1) == 0)) {
  259.         printf("Can't write to terminal; status=%d, iosb=%d\n",
  260.             status, iosb[0]);
  261.         exit(status);
  262.     }
  263.     return 0;    /* Success */
  264. }
  265.  
  266.  
  267. /*
  268.  * __ttputc - Write a character to the display. Actually save it in our buffer
  269.  * and write it only if the buffer is becoming full.
  270.  * This function is called by TTPUTC().
  271.  */
  272. __ttputc(c)
  273. {
  274.     OutputBuffer[OutputBufferCounter++] = c;
  275.     if(OutputBufferCounter >= MAXBUF)
  276.         ttflush();
  277.     return c;
  278. }
  279.  
  280. /*
  281.  * ttputc - Write a character to the display. Actually save it in our buffer
  282.  * and write it only if the buffer is becoming full.
  283.  */
  284. #undef ttputc
  285. ttputc(c)
  286. {
  287.     return(__ttputc(c));
  288. }
  289.  
  290.  
  291. /*
  292.  * ttflush - Flush our buffer to the terminal.
  293.  */
  294. ttflush()
  295. {
  296.     if(OutputBufferCounter > 0) {
  297.         write_terminal(OutputBuffer, OutputBufferCounter);
  298.         OutputBufferCounter = 0;
  299.     }
  300. }
  301.  
  302.  
  303. /*
  304.  * ttgetc - Read a character from the terminal, performing no editing 
  305.  *          and doing no echo at all.
  306.  */
  307. ttgetc()
  308. {
  309.     unsigned char c;
  310.     int i;
  311.     long    status;
  312.     unsigned long Terminator[4] = { -1, -1, -1, -1};
  313.     struct DESC    TerminatorDesc = { sizeof(Terminator), 0, Terminator };
  314.     short    iosb[4];
  315.  
  316.     status = sys$qiow((int)(0), TerminalChan,
  317.         (short)(IO$_READLBLK | IO$M_NOFORMAT | IO$M_NOFILTR | IO$M_NOECHO | IO$M_TRMNOECHO),
  318.             iosb, (int)(0), (int)(0),
  319.             &c, 1, (int)(0), &TerminatorDesc, (int)(0), (int)(0));
  320.     if(((status & 0x1) == 0) || ((iosb[0] & 0x1) == 0)) {
  321.         printf("Can't read from terminal; status=%d, iosb=%d\n",
  322.             status, iosb[0]);
  323.         exit(status);
  324.     }
  325.  
  326.     c &= 0xff;
  327.     if(c == 155) c = 27;    /* Convert 8th bit escape to 7bit one */
  328.     return((int)(c));
  329. }
  330.  
  331.  
  332. /*
  333.  * GetKey - Read in a key.
  334.  * Do the standard keyboard preprocessing. Convert the keys to the internal
  335.  * character set.  Resolves escape sequences and returns no-op if global
  336.  * timeout value exceeded.
  337.  */
  338. GetKey()
  339. {
  340.     int    c, status, cc;
  341.  
  342. /*~~~ HUJI/VMS - No timeout is supported on VMS to make it simple... */
  343.  
  344.     switch(status = kbseq(pico_kbesc, term.t_getchar, &c)){
  345.       case 0:     /* regular character */
  346.     break;
  347.  
  348.       case K_DOUBLE_ESC:
  349.     c = (*term.t_getchar)();
  350.  
  351.     if(islower((unsigned char)c))    /* canonicalize c */
  352.       c = toupper((unsigned char)c);
  353.  
  354.     return((isalpha((unsigned char)c) || c == '@' || (c >= '[' && c <= '_'))
  355.            ? (CTRL | c) : c);
  356.  
  357.       case  K_PAD_UP        :
  358.       case  K_PAD_DOWN        :
  359.       case  K_PAD_RIGHT        :
  360.       case  K_PAD_LEFT        :
  361.       case  K_PAD_PREVPAGE    :
  362.       case  K_PAD_NEXTPAGE    :
  363.       case  K_PAD_HOME        :
  364.       case  K_PAD_END        :
  365.       case  K_PAD_DELETE    :
  366.       case F1  :
  367.       case F2  :
  368.       case F3  :
  369.       case F4  :
  370.       case F5  :
  371.       case F6  :
  372.       case F7  :
  373.       case F8  :
  374.       case F9  :
  375.       case F10 :
  376.       case F11 :
  377.       case F12 :
  378.     return(status);
  379.  
  380.       case K_SWALLOW_TIL_Z:
  381.     status = NODATA;
  382.       case K_SWALLOW_UP:
  383.       case K_SWALLOW_DOWN:
  384.       case K_SWALLOW_LEFT:
  385.       case K_SWALLOW_RIGHT:
  386.     for(cc = 0; cc != 'z' && cc != '~';)
  387.       cc = (*term.t_getchar)() & 0x7f;
  388.  
  389.     return(status);
  390.     break;
  391.  
  392.       case K_KERMIT:
  393.     for(cc = 0; cc != '\033' || ((*term.t_getchar)() & 0x7f) != '\\';)
  394.       cc = (*term.t_getchar)() & 0x7f;
  395.  
  396.     c = NODATA;
  397.     break;
  398.  
  399.       case BADESC:
  400.     (*term.t_beep)();
  401.     return(status);
  402.  
  403.       default:                /* punt the whole thing    */
  404.     (*term.t_beep)();
  405.     break;
  406.     }
  407.  
  408.     if (c>=0x00 && c<=0x1F)                 /* C0 control -> C-     */
  409.       c = CTRL | (c+'@');
  410.  
  411.     return (c);
  412. }
  413.  
  414.  
  415. /* 
  416.  * kbseq - looks at an escape sequence coming from the keyboard and 
  417.  *         compares it to a trie of known keyboard escape sequences, and
  418.  *         performs the function bound to the escape sequence.
  419.  * 
  420.  *         returns: BADESC, the escaped function, or 0 if a regular char.
  421.  */
  422. kbseq(trie, getcfunc, c)
  423.     KBESC_T *trie;
  424.     int    (*getcfunc)();
  425.     int        *c;
  426. {
  427.     register char     b;
  428.     register int      first = 1;
  429.     register KBESC_T *current = trie;
  430.  
  431.     if(trie == NULL)                /* bag it */
  432.       return(BADESC);
  433.  
  434.     while(1){
  435.     b = *c = (*getcfunc)();
  436.  
  437.     while(current->value != b){
  438.         if(current->left == NULL){        /* NO MATCH */
  439.         if(first)
  440.           return(0);            /* regular char */
  441.         else
  442.           return(BADESC);
  443.         }
  444.         current = current->left;
  445.     }
  446.  
  447.     if(current->down == NULL)        /* match!!!*/
  448.       return(current->func);
  449.     else
  450.       current = current->down;
  451.  
  452.     first = 0;
  453.     }
  454. }
  455.  
  456.  
  457. /*
  458.  * alt_editor - Use normal SYSTEM() and not fork.
  459.  */
  460. alt_editor(f, n)
  461. {
  462.     char   eb[NLINE];                /* buf holding edit command */
  463.     char   *fn;                    /* tmp holder for file name */
  464.     char   *cp;
  465.     long   l;
  466.     int    i, pid, done = 0;
  467.  
  468.     if(Pmaster == NULL)
  469.       return;
  470.  
  471.     if(gmode&MDSCUR){
  472.     emlwrite("Alternate editor not available in restricted mode", NULL);
  473.     return;
  474.     }
  475.  
  476.     if(Pmaster->alt_ed == NULL){
  477.     if(!(gmode&MDADVN)){
  478.         emlwrite("\007Unknown Command",NULL);
  479.         return;
  480.     }
  481.  
  482.     if(getenv("EDITOR"))
  483.       strcpy(eb, (char *)getenv("EDITOR"));
  484.     else
  485.       *eb = '\0';
  486.  
  487.     while(!done){
  488.         pid = mlreplyd("Which alternate editor ? ", eb, NLINE, QDEFLT);
  489.  
  490.         switch(pid){
  491.           case ABORT:
  492.         return(-1);
  493.           case HELPCH:
  494.         emlwrite("no alternate editor help yet", NULL);
  495.  
  496. /* take sleep and break out after there's help */
  497.         sleep(3);
  498.         break;
  499.           case (CTRL|'L'):
  500.         sgarbf = TRUE;
  501.         update();
  502.         break;
  503.           case TRUE:
  504.           case FALSE:            /* does editor exist ? */
  505.         if(*eb == '\0'){        /* leave silently? */
  506.             mlerase();
  507.             return(-1);
  508.         }
  509.  
  510.         done++;
  511.         break;
  512.           default:
  513.         break;
  514.         }
  515.     }
  516.     }
  517.     else
  518.       strcpy(eb, Pmaster->alt_ed);
  519.  
  520.     if((fn=writetmp(0, 1)) == NULL){        /* get temp file */
  521.     emlwrite("Problem writing temp file for alt editor", NULL);
  522.     return(-1);
  523.     }
  524.  
  525.     strcat(eb, " ");
  526.  
  527. /* fn is /SYS$SCRATCH/filename;  Modify it to suit DCL style... */
  528.     if((cp = strrchr(fn, '/')) != NULL) {
  529.     strcat(eb, "SYS$SCRATCH:"); strcat(eb, &cp[1]);
  530.     } else strcat(eb, fn);
  531.  
  532.     cp = eb;
  533.  
  534.     if(Pmaster)
  535.       (*Pmaster->raw_io)(0);            /* turn OFF raw mode */
  536.  
  537.     system(eb);
  538.     if(Pmaster)
  539.       (*Pmaster->raw_io)(1);        /* turn ON raw mode */
  540.  
  541.     /*
  542.      * replace edited text with new text 
  543.      */
  544.     curbp->b_flag &= ~BFCHG;        /* make sure old text gets blasted */
  545.     readin(fn, 0);            /* read new text overwriting old */
  546.     unlink(fn);                /* blast temp file */
  547.     curbp->b_flag |= BFCHG;        /* mark dirty for packbuf() */
  548.     ttopen();                /* reset the signals */
  549.     refresh(0, 1);            /* redraw */
  550. }
  551.  
  552.  
  553.  
  554. /*
  555.  *  bktoshell - suspend and wait to be woken up
  556.  */
  557. bktoshell()        /* suspend MicroEMACS and wait to wake up */
  558. {
  559.     emlwrite("\007Unknown command (in BktoShell): ^Z", NULL);
  560.     return;
  561. }
  562.  
  563.  
  564. /* 
  565.  * rtfrmshell - back from shell, fix modes and return
  566.  */
  567. SIGTYPE
  568. rtfrmshell()
  569. {
  570. }
  571.  
  572.  
  573. /*
  574.  * do_hup_signal - jump back in the stack to where we can handle this
  575.  */
  576. SIGTYPE
  577. do_hup_signal()
  578. {
  579.     if(Pmaster){
  580.     extern jmp_buf finstate;
  581.  
  582.     signal(SIGHUP, SIG_IGN);         /* don't bother us. */
  583.     signal(SIGTERM, SIG_IGN);
  584.     longjmp(finstate, COMP_GOTHUP);
  585.     }
  586.     else{
  587.     /*
  588.      * if we've been interrupted and the buffer is changed,
  589.      * save it...
  590.      */
  591.     if(anycb() == TRUE){            /* time to save */
  592.         if(curbp->b_fname[0] == '\0'){    /* name it */
  593.         strcpy(curbp->b_fname, "pico.save");
  594.         }
  595.         else{
  596.         strcat(curbp->b_fname, ".save");
  597.         }
  598.         writeout(curbp->b_fname);
  599.     }
  600.     vttidy();
  601.     exit(1);
  602.     }
  603. }
  604.  
  605.  
  606. unlink(fn)
  607. char    *fn;
  608. {
  609.     delete(fn);
  610. }
  611.  
  612. /*
  613.  * big bitmap of ASCII characters allowed in a file name
  614.  * (needs reworking for other char sets)
  615.  */
  616. unsigned char okinfname[32] = {
  617.       0,    0,             /* ^@ - ^G, ^H - ^O  */
  618.       0,    0,            /* ^P - ^W, ^X - ^_  */
  619.       0xff, 0xff,        /* SP - ' ,  ( - /   */
  620.       0xff, 0xff,        /*  0 - 7 ,  8 - ?   */
  621.       0xff, 0xff,        /*  @ - G ,  H - O   */
  622.       0xff, 0xff,        /*  P - W ,  X - _   */
  623.       0xff, 0xff,        /*  ` - g ,  h - o   */
  624.       0xff, 0xff,        /*  p - w ,  x - DEL */
  625.       0,    0,             /*  > DEL   */
  626.       0,    0,            /*  > DEL   */
  627.       0,    0,             /*  > DEL   */
  628.       0,    0,             /*  > DEL   */
  629.       0,    0             /*  > DEL   */
  630. };
  631.  
  632.  
  633. /*
  634.  * fallowc - returns TRUE if c is allowable in filenames, FALSE otw
  635.  */
  636. fallowc(c)
  637. char c;
  638. {
  639.     return(okinfname[c>>3] & 0x80>>(c&7));
  640. }
  641.  
  642.  
  643. /*
  644.  * fexist - returns TRUE if the file exists with mode passed in m, 
  645.  *          FALSE otherwise.  By side effect returns length of file in l
  646.  */
  647. fexist(file, m, l)
  648. char *file;
  649. char *m;                    /* files mode: r, w or rw */
  650. long *l;
  651. {
  652.     struct stat    sbuf;
  653.  
  654.     if(l)
  655.       *l = 0L;
  656.  
  657.     if(stat(file, &sbuf) < 0){
  658.     switch(errno){
  659.       case ENOENT :                /* File not found */
  660.         return(FIOFNF);
  661. #ifdef    ENAMETOOLONG
  662.       case ENAMETOOLONG :            /* Name is too long */
  663.         return(FIOLNG);
  664. #endif
  665.       default:                /* Some other error */
  666.         return(FIOERR);
  667.     }
  668.     }
  669.  
  670.     if(l)
  671.       *l = sbuf.st_size;
  672.  
  673.     if((sbuf.st_mode&S_IFMT) == S_IFDIR)
  674.       return(FIODIR);
  675.     else if(*m == 't')                /* no links, just say yes */
  676.       return(FIOSUC);
  677.  
  678.     if(*m == 'r'){
  679.     if(*(m+1) == 'w')            /* read access? */
  680.       return((S_IREAD&sbuf.st_mode)
  681.          ? ((S_IWRITE&sbuf.st_mode))
  682.             ? FIOSUC
  683.             : FIONWT
  684.          : FIONRD);
  685.     else
  686.       return((S_IREAD&sbuf.st_mode) ? FIOSUC : FIONRD);
  687.     }
  688.     else if(*m == 'w')                /* write access? */
  689.       return((S_IWRITE&sbuf.st_mode) ? FIOSUC : FIONWT);
  690.     else if(*m == 'x')                /* execute access? */
  691.       return((S_IEXEC&sbuf.st_mode) ? FIOSUC : FIONEX);
  692.     return(FIOERR);                /* what? */
  693. }
  694.  
  695.  
  696. /*
  697.  * isdir - returns true if fn is a readable directory, false otherwise
  698.  *         silent on errors (we'll let someone else notice the problem;)).
  699.  */
  700. isdir(fn, l)
  701. char *fn;
  702. long *l;
  703. {
  704.     struct stat sbuf;
  705.  
  706.     if(l)
  707.       *l = 0;
  708.  
  709.     if(stat(fn, &sbuf) < 0)
  710.       return(0);
  711.  
  712.     if(l)
  713.       *l = sbuf.st_size;
  714.     return((sbuf.st_mode&S_IFMT) == S_IFDIR);
  715. }
  716.  
  717.  
  718.  
  719. /*
  720.  * gethomedir - returns the users home directory
  721.  *              Note: home is malloc'd for life of pico
  722.  */
  723. char *
  724. gethomedir(l)
  725. int *l;
  726. {
  727.     static char *home = NULL;
  728.     static short hlen = 0;
  729.     char   s[1024];
  730.  
  731.     if(home == NULL){
  732.     strcpy(s, getenv("HOME"));
  733.     hlen = strlen(s);
  734.     if((home=(char *)malloc((strlen(s) + 1) * sizeof(char))) == NULL){
  735.         emlwrite("Problem allocating space for home dir", NULL);
  736.         return(0);
  737.     }
  738.     strcpy(home, s);
  739.     }
  740.  
  741.     if(l)
  742.       *l = hlen;
  743.  
  744.     return(home);
  745. }
  746.  
  747.  
  748. /*
  749.  * homeless - returns true if given file does not reside in the current
  750.  *            user's home directory tree. 
  751.  */
  752. homeless(f)
  753. char *f;
  754. {
  755.     char *home;
  756.     int   len;
  757.  
  758.     home = gethomedir(&len);
  759.     return(strncmp(home, f, len));
  760. }
  761.  
  762.  
  763.  
  764. /*
  765.  * errstr - return system error string corresponding to given errno
  766.  *          Note: strerror() is not provided on all systems, so it's 
  767.  *          done here once and for all.
  768.  */
  769. char *
  770. errstr(err)
  771. int err;
  772. {
  773.     extern char *sys_errlist[];
  774.     extern int  sys_nerr;
  775.  
  776.     return((err >= 0 && err < sys_nerr) ? sys_errlist[err] : NULL);
  777. }
  778.  
  779.  
  780.  
  781. /*
  782.  * getfnames - return all file names in the given directory in a single 
  783.  *             malloc'd string.  n contains the number of names
  784.  */
  785. char *
  786. getfnames(dn, pat, n, e)
  787. char *dn, *pat, *e;
  788. int  *n;
  789. {
  790.     char    *ddn;        /* Don't ruin the original */
  791.     int    context = 0;    /* Used in LIB$FIND_FILE */
  792.     struct    DESC    file_mask, file_name;
  793.     int    status;
  794.     char    *p, *OutputPointer;
  795.     char    *RetFiles = malloc(8192);    /* Hopefully it will be enough... */
  796.     char    FileName[256];    /* Temporary place */
  797.  
  798.     *n = 0;        /* Init - no files yet */
  799.     if(RetFiles == NULL) return;
  800.     *(OutputPointer = RetFiles) = '\0';
  801.  
  802. /* For all directory names append *.* for the finction to succeed */
  803.     strcpy(ddn, dn);    /* Don't ruin it */
  804.     strcat(ddn, "*.*");
  805.  
  806.     file_mask.length = strlen(ddn); file_mask.address = ddn;
  807.     file_mask.type = 0;
  808.  
  809.     for(;;) {
  810.         file_name.address = FileName; file_name.length = sizeof(FileName) - 1;
  811.         file_name.type = 0;
  812.  
  813.         status = LIB$FIND_FILE(&file_mask, &file_name, &context);
  814.         if((status & 0x1) == 0) {
  815.             if(context != 0)
  816.                 LIB$FIND_FILE_END(&context);
  817.             context = 0;    /* Init for next search */
  818.             return RetFiles;
  819.         }
  820.  
  821. /* File found - Remove the leading directory name and the trailing spaces */
  822.         if((p = strchr(FileName, ' ')) != NULL) *p = '\0';
  823.         if((p = strrchr(FileName, ']')) != NULL) p++;
  824.         else                    p = FileName;
  825.  
  826.         if(!pat || !*pat || strucmp(p, pat, strlen(pat))){
  827.             while((*OutputPointer++ = *p++) != '\0');
  828.             *n += 1;
  829.         }
  830.     }
  831. }
  832.  
  833.  
  834. /*
  835.  * fioperr - given the error number and file name, display error
  836.  */
  837. void
  838. fioperr(e, f)
  839. int  e;
  840. char *f;
  841. {
  842.     switch(e){
  843.       case FIOFNF:                /* File not found */
  844.     emlwrite("\007File \"%s\" not found", f);
  845.     break;
  846.       case FIOEOF:                /* end of file */
  847.     emlwrite("\007End of file \"%s\" reached", f);
  848.     break;
  849.       case FIOLNG:                /* name too long */
  850.     emlwrite("\007File name \"%s\" too long", f);
  851.     break;
  852.       case FIODIR:                /* file is a directory */
  853.     emlwrite("\007File \"%s\" is a directory", f);
  854.     break;
  855.       case FIONWT:
  856.     emlwrite("\007Write permission denied: %s", f);
  857.     break;
  858.       case FIONRD:
  859.     emlwrite("\007Read permission denied: %s", f);
  860.     break;
  861.       case FIONEX:
  862.     emlwrite("\007Execute permission denied: %s", f);
  863.     break;
  864.       default:
  865.     emlwrite("\007File I/O error: %s", f);
  866.     }
  867. }
  868.  
  869.  
  870.  
  871. /*
  872.  * pfnexpand - pico's function to expand the given file name if there is 
  873.  *           a leading '~'
  874.  */
  875. char *pfnexpand(fn, len)
  876. char *fn;
  877. int  len;
  878. {
  879.     char    *pw;
  880.     register char *x, *y, *z;
  881.     char name[256];
  882.     
  883.     if(*fn == '~') {
  884.         for(x = fn+1, y = name; *x != '/' && *x != '\0'; *y++ = *x++);
  885.         *y = '\0';
  886.         if(x == fn + 1) 
  887.           pw = getenv("HOME");
  888.         else
  889.           pw = NULL;
  890.         if(pw == NULL)
  891.           return(NULL);
  892.  
  893.     /* make room for expanded path */
  894.     for(z=x+strlen(x),y=fn+strlen(x)+strlen(pw);
  895.         z >= x;
  896.         *y-- = *z--);
  897.     /* and insert the expanded address */
  898.     for(x=fn,y=pw; *y != '\0'; *x++ = *y++);
  899.     }
  900.     return(fn);
  901. }
  902.  
  903.  
  904.  
  905. /*
  906.  * fixpath - do nothing...
  907.  */
  908. fixpath(name, len)
  909. char *name;
  910. int  len;
  911. {
  912. }
  913.  
  914.  
  915. /*
  916.  * compresspath - given a base path and an additional directory, collapse
  917.  *                ".." and "." elements and return absolute path (appending
  918.  *                base if necessary).  
  919.  *
  920.  *                returns  1 if OK, 
  921.  *                         0 if there's a problem
  922.  *                         new path, by side effect, if things went OK
  923.  */
  924. compresspath(base, path, len)
  925. char *base, *path;
  926. int  len;
  927. {
  928.     register int i;
  929.     int  depth = 0;
  930.     char *p;
  931.     char *stack[32];
  932.     char s[1024];
  933.  
  934. #define PUSHD(X)  (stack[depth++] = X)
  935. #define POPD()    ((depth > 0) ? stack[--depth] : "")
  936.  
  937.     if(*path == '~'){
  938.     fixpath(path, len);
  939.     strcpy(s, path);
  940.     }
  941.     else if(*path != C_FILESEP)
  942.       sprintf(s, "%s%c%s", base, C_FILESEP, path);
  943.     else
  944.       strcpy(s, path);
  945.  
  946.     p = s;
  947.     for(i=0; s[i] != '\0'; i++){        /* pass thru path name */
  948.     if(s[i] == '/'){
  949.         if(p != s)
  950.           PUSHD(p);                /* push dir entry */
  951.         p = &s[i+1];            /* advance p */
  952.         s[i] = '\0';            /* cap old p off */
  953.         continue;
  954.     }
  955.  
  956.     if(s[i] == '.'){            /* special cases! */
  957.         if(s[i+1] == '.'            /* parent */
  958.            && (s[i+2] == '/' || s[i+2] == '\0')){
  959.         if(!strcmp(POPD(),""))        /* bad news! */
  960.           return(0);
  961.  
  962.         i += 2;
  963.         p = (s[i] == '\0') ? "" : &s[i+1];
  964.         }
  965.         else if(s[i+1] == '/' || s[i+1] == '\0'){        /* no op */
  966.         i++;
  967.         p = (s[i] == '\0') ? "" : &s[i+1];
  968.         }
  969.     }
  970.     }
  971.  
  972.     if(*p != '\0')
  973.       PUSHD(p);                    /* get last element */
  974.  
  975.     path[0] = '\0';
  976.     for(i = 0; i < depth; i++){
  977.     strcat(path, S_FILESEP);
  978.     strcat(path, stack[i]);
  979.     }
  980.  
  981.     return(1);                    /* everything's ok */
  982. }
  983.  
  984.  
  985. /*
  986.  * tmpname - return a temporary file name in the given buffer
  987.  */
  988. void
  989. tmpname(name)
  990. char *name;
  991. {
  992.     sprintf(name, "/SYS$SCRATCH/pico.%d", getpid());    /* tmp file name */
  993. }
  994.  
  995.  
  996. /*
  997.  * Take a file name, and from it
  998.  * fabricate a buffer name. This routine knows
  999.  * about the syntax of file names on the target system.
  1000.  * I suppose that this information could be put in
  1001.  * a better place than a line of code.
  1002.  */
  1003. void
  1004. makename(bname, fname)
  1005. char    bname[];
  1006. char    fname[];
  1007. {
  1008.     register char   *cp1;
  1009.     register char   *cp2;
  1010.  
  1011.     cp1 = &fname[0];
  1012.     while (*cp1 != 0)
  1013.       ++cp1;
  1014.  
  1015.     while (cp1!=&fname[0] && cp1[-1]!='/')
  1016.       --cp1;
  1017.  
  1018.     cp2 = &bname[0];
  1019.     while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';')
  1020.       *cp2++ = *cp1++;
  1021.  
  1022.     *cp2 = 0;
  1023. }
  1024.  
  1025.  
  1026. /*
  1027.  * copy - copy contents of file 'a' into a file named 'b'.  Return error
  1028.  *        if either isn't accessible or is a directory
  1029.  */
  1030. copy(a, b)
  1031. char *a, *b;
  1032. {
  1033.     int    in, out, n, rv = 0;
  1034.     char   *cb;
  1035.     struct stat tsb, fsb;
  1036.     extern int  errno;
  1037.  
  1038.     if(stat(a, &fsb) < 0){        /* get source file info */
  1039.     emlwrite("Can't Copy: %s", errstr(errno));
  1040.     return(-1);
  1041.     }
  1042.  
  1043.     if(!(fsb.st_mode&S_IREAD)){        /* can we read it? */
  1044.     emlwrite("\007Read permission denied: %s", a);
  1045.     return(-1);
  1046.     }
  1047.  
  1048.     if((fsb.st_mode&S_IFMT) == S_IFDIR){ /* is it a directory? */
  1049.     emlwrite("\007Can't copy: %s is a directory", a);
  1050.     return(-1);
  1051.     }
  1052.  
  1053.     if(stat(b, &tsb) < 0){        /* get dest file's mode */
  1054.     switch(errno){
  1055.       case ENOENT:
  1056.         break;            /* these are OK */
  1057.       default:
  1058.         emlwrite("\007Can't Copy: %s", errstr(errno));
  1059.         return(-1);
  1060.     }
  1061.     }
  1062.     else{
  1063.     if(!(tsb.st_mode&S_IWRITE)){    /* can we write it? */
  1064.         emlwrite("\007Write permission denied: %s", b);
  1065.         return(-1);
  1066.     }
  1067.  
  1068.     if((tsb.st_mode&S_IFMT) == S_IFDIR){    /* is it directory? */
  1069.         emlwrite("\007Can't copy: %s is a directory", b);
  1070.         return(-1);
  1071.     }
  1072.  
  1073.     if(fsb.st_dev == tsb.st_dev && fsb.st_ino == tsb.st_ino){
  1074.         emlwrite("\007Identical files.  File not copied", NULL);
  1075.         return(-1);
  1076.     }
  1077.     }
  1078.  
  1079.     if((in = open(a, O_RDONLY)) < 0){
  1080.     emlwrite("Copy Failed: %s", errstr(errno));
  1081.     return(-1);
  1082.     }
  1083.  
  1084.     if((out=creat(b, fsb.st_mode&0xfff)) < 0){
  1085.     emlwrite("Can't Copy: %s", errstr(errno));
  1086.     close(in);
  1087.     return(-1);
  1088.     }
  1089.  
  1090.     if((cb = (char *)malloc(NLINE*sizeof(char))) == NULL){
  1091.     emlwrite("Can't allocate space for copy buffer!", NULL);
  1092.     close(in);
  1093.     close(out);
  1094.     return(-1);
  1095.     }
  1096.  
  1097.     while(1){                /* do the copy */
  1098.     if((n = read(in, cb, NLINE)) < 0){
  1099.         emlwrite("Can't Read Copy: %s", errstr(errno));
  1100.         rv = -1;
  1101.         break;            /* get out now */
  1102.     }
  1103.  
  1104.     if(n == 0)            /* done! */
  1105.       break;
  1106.  
  1107.     if(write(out, cb, n) != n){
  1108.         emlwrite("Can't Write Copy: %s", errstr(errno));
  1109.         rv = -1;
  1110.         break;
  1111.     }
  1112.     }
  1113.  
  1114.     free(cb);
  1115.     close(in);
  1116.     close(out);
  1117.     return(rv);
  1118. }
  1119.  
  1120.  
  1121. /*
  1122.  * Open a file for writing. Return TRUE if all is well, and FALSE on error
  1123.  * (cannot create).
  1124.  */
  1125. ffwopen(fn)
  1126. char    *fn;
  1127. {
  1128.     extern FILE *ffp;
  1129.  
  1130.     if ((ffp=fopen(fn, "w")) == NULL) {
  1131.         emlwrite("Cannot open file for writing", NULL);
  1132.         return (FIOERR);
  1133.     }
  1134.  
  1135.     return (FIOSUC);
  1136. }
  1137.  
  1138.  
  1139. /*
  1140.  * Close a file. Should look at the status in all systems.
  1141.  */
  1142. ffclose()
  1143. {
  1144.     extern FILE *ffp;
  1145.  
  1146.     if (fclose(ffp) != FALSE) {
  1147.         emlwrite("Error closing file", NULL);
  1148.         return(FIOERR);
  1149.     }
  1150.  
  1151.     return(FIOSUC);
  1152. }
  1153.  
  1154.  
  1155. /*
  1156.  * ffelbowroom - make sure the destination's got enough room to receive
  1157.  *         what we're about to write...
  1158.  */
  1159. ffelbowroom(fn)
  1160. char    *fn;
  1161. {
  1162.     return(TRUE);
  1163. }
  1164.  
  1165.  
  1166. /*
  1167.  * P_open - run the given command in a sub-shell returning a file pointer
  1168.  *        from which to read the output
  1169.  *
  1170.  * note:
  1171.  *    For OS's other than unix, you will have to rewrite this function.
  1172.  *    Hopefully it'll be easy to exec the command into a temporary file, 
  1173.  *    and return a file pointer to that opened file or something.
  1174.  */
  1175. FILE *P_open(s)
  1176. char *s;
  1177. {
  1178.     printf("Popen not supported on VMS yet.\n");
  1179.     return NULL;
  1180. }
  1181.  
  1182.  
  1183.  
  1184. /*
  1185.  * P_close - close the given descriptor
  1186.  *
  1187.  */
  1188. P_close(fp)
  1189. FILE *fp;
  1190. {
  1191.     return;
  1192. }
  1193.  
  1194.  
  1195.  
  1196. /*
  1197.  * worthit - generic sort of test to roughly gage usefulness of using 
  1198.  *           optimized scrolling.
  1199.  *
  1200.  * note:
  1201.  *    returns the line on the screen, l, that the dot is currently on
  1202.  */
  1203. worthit(l)
  1204. int *l;
  1205. {
  1206.     int i;            /* l is current line */
  1207.     unsigned below;        /* below is avg # of ch/line under . */
  1208.  
  1209.     *l = doton(&i, &below);
  1210.     below = (i > 0) ? below/(unsigned)i : 0;
  1211.  
  1212.     return(below > 3);
  1213. }
  1214.  
  1215.  
  1216.  
  1217. /*
  1218.  * pico_new_mail - just checks mtime and atime of mail file and notifies user 
  1219.  *               if it's possible that they have new mail.
  1220.  */
  1221. pico_new_mail()
  1222. {
  1223.     int ret = 0;
  1224.     static time_t lastchk = 0;
  1225.     struct stat sbuf;
  1226.     char   inbox[256], *p;
  1227.  
  1228.     sprintf(inbox,"SYS$LOGIN:MAIL.MAI");
  1229.  
  1230.     if(stat(inbox, &sbuf) == 0){
  1231.     ret = sbuf.st_atime <= sbuf.st_mtime &&
  1232.       (lastchk < sbuf.st_mtime && lastchk < sbuf.st_atime);
  1233.     lastchk = sbuf.st_mtime;
  1234.     return(ret);
  1235.     }
  1236.     else
  1237.       return(ret);
  1238. }
  1239.  
  1240.  
  1241.  
  1242. /*
  1243.  * time_to_check - checks the current time against the last time called 
  1244.  *                 and returns true if the elapsed time is > timeout
  1245.  */
  1246. time_to_check()
  1247. {
  1248.     static time_t lasttime = 0L;
  1249.  
  1250.     if(!timeout)
  1251.       return(FALSE);
  1252.  
  1253.     if(time((long *) 0) - lasttime > (time_t)timeout){
  1254.     lasttime = time((long *) 0);
  1255.     return(TRUE);
  1256.     }
  1257.     else
  1258.       return(FALSE);
  1259. }
  1260.  
  1261.  
  1262. /*
  1263.  * sstrcasecmp - compare two pointers to strings case independently
  1264.  */
  1265. sstrcasecmp(s1, s2)
  1266. QcompType *s1, *s2;
  1267. {
  1268.     register char *a, *b;
  1269.  
  1270.     a = *(char **)s1;
  1271.     b = *(char **)s2;
  1272.     while(toupper((unsigned char)(*a)) == toupper((unsigned char)(*b++)))
  1273.     if(*a++ == '\0')
  1274.       return(0);
  1275.  
  1276.     return(toupper((unsigned char)(*a)) - toupper((unsigned char)(*--b)));
  1277. }
  1278.  
  1279.  
  1280. /*
  1281.  * chkptinit -- initialize anything we need to support composer
  1282.  *        checkpointing
  1283.  */
  1284. chkptinit(file, n)
  1285.     char *file;
  1286.     int   n;
  1287. {
  1288.     unsigned pid;
  1289.     char    *chp;
  1290.     long     gmode_save;
  1291.  
  1292.     gmode_save = gmode;
  1293.     if(gmode&MDCURDIR)
  1294.       gmode &= ~MDCURDIR;  /* so fixpath will use home dir */
  1295.  
  1296.     strcpy(file, "#picoXXXXX#");
  1297.     fixpath(file, NLINE);
  1298.     pid = (unsigned)getpid();
  1299.     for(chp = file + strlen(file) - 2; *chp == 'X'; chp--){
  1300.     *chp = (pid % 10) + '0';
  1301.     pid /= 10;
  1302.     }
  1303.  
  1304.     gmode = gmode_save;
  1305.     unlink(file);
  1306. }
  1307.  
  1308.  
  1309. #ifdef    TIOCGWINSZ
  1310. /*
  1311.  * winch_handler - handle window change signal
  1312.  */
  1313. SIGTYPE winch_handler()
  1314. {
  1315.     struct winsize win;
  1316.     extern int resize_pico();
  1317.  
  1318.     signal(SIGWINCH, winch_handler);
  1319.  
  1320.     if (ioctl(0, TIOCGWINSZ, &win) == 0) {
  1321.     if (win.ws_col && win.ws_row)
  1322.       resize_pico(win.ws_row - 1, win.ws_col);
  1323.     }
  1324. }
  1325. #endif    /* TIOCGWINSZ */
  1326.  
  1327.  
  1328. /* Copied from TCAP */
  1329. hide_cur()
  1330. {
  1331. write_terminal("\033[?25l", 6);
  1332. }
  1333. show_cur()
  1334. {
  1335. write_terminal("\033[?25h", 6);
  1336. }
  1337.  
  1338. o_insert()
  1339. {
  1340.     return 0;
  1341. }
  1342.  
  1343. o_delete()
  1344. {
  1345.     return 0;
  1346. }
  1347.  
  1348.  
  1349. /*
  1350.  * add default keypad sequences to the trie...
  1351.  */
  1352. init_kpnames()
  1353. {
  1354.     /* 
  1355.      * UW-NDC/UCS vt10[02] application mode.
  1356.      */
  1357.     kpinsert(&pico_kbesc, "\033OP", F1);
  1358.     kpinsert(&pico_kbesc, "\033OQ", F2);
  1359.     kpinsert(&pico_kbesc, "\033OR", F3);
  1360.     kpinsert(&pico_kbesc, "\033OS", F4);
  1361.     kpinsert(&pico_kbesc, "\033Op", F5);
  1362.     kpinsert(&pico_kbesc, "\033Oq", F6);
  1363.     kpinsert(&pico_kbesc, "\033Or", F7);
  1364.     kpinsert(&pico_kbesc, "\033Os", F8);
  1365.     kpinsert(&pico_kbesc, "\033Ot", F9);
  1366.     kpinsert(&pico_kbesc, "\033Ou", F10);
  1367.     kpinsert(&pico_kbesc, "\033Ov", F11);
  1368.     kpinsert(&pico_kbesc, "\033Ow", F12);
  1369.  
  1370.     /*
  1371.      * DC vt100, ANSI and cursor key mode.
  1372.      */
  1373.     kpinsert(&pico_kbesc, "\033OA", K_PAD_UP);
  1374.     kpinsert(&pico_kbesc, "\033OB", K_PAD_DOWN);
  1375.     kpinsert(&pico_kbesc, "\033OC", K_PAD_RIGHT);
  1376.     kpinsert(&pico_kbesc, "\033OD", K_PAD_LEFT);
  1377.  
  1378.     /*
  1379.      * special keypad functions
  1380.      */
  1381.     kpinsert(&pico_kbesc, "\033[4J", K_PAD_PREVPAGE);
  1382.     kpinsert(&pico_kbesc, "\033[3J", K_PAD_NEXTPAGE);
  1383.     kpinsert(&pico_kbesc, "\033[2J", K_PAD_HOME);
  1384.     kpinsert(&pico_kbesc, "\033[N",  K_PAD_END);
  1385.  
  1386.     /* 
  1387.      * ANSI mode.
  1388.      */
  1389.     kpinsert(&pico_kbesc, "\033[=a", F1);
  1390.     kpinsert(&pico_kbesc, "\033[=b", F2);
  1391.     kpinsert(&pico_kbesc, "\033[=c", F3);
  1392.     kpinsert(&pico_kbesc, "\033[=d", F4);
  1393.     kpinsert(&pico_kbesc, "\033[=e", F5);
  1394.     kpinsert(&pico_kbesc, "\033[=f", F6);
  1395.     kpinsert(&pico_kbesc, "\033[=g", F7);
  1396.     kpinsert(&pico_kbesc, "\033[=h", F8);
  1397.     kpinsert(&pico_kbesc, "\033[=i", F9);
  1398.     kpinsert(&pico_kbesc, "\033[=j", F10);
  1399.     kpinsert(&pico_kbesc, "\033[=k", F11);
  1400.     kpinsert(&pico_kbesc, "\033[=l", F12);
  1401.  
  1402.     /*
  1403.      * DEC vt100, ANSI, cursor key mode reset.
  1404.      */
  1405.     kpinsert(&pico_kbesc, "\033[A", K_PAD_UP);
  1406.     kpinsert(&pico_kbesc, "\033[B", K_PAD_DOWN);
  1407.     kpinsert(&pico_kbesc, "\033[C", K_PAD_RIGHT);
  1408.     kpinsert(&pico_kbesc, "\033[D", K_PAD_LEFT);
  1409.  
  1410.     /*
  1411.      * DEC vt52 mode.
  1412.      */
  1413.     kpinsert(&pico_kbesc, "\033A", K_PAD_UP);
  1414.     kpinsert(&pico_kbesc, "\033B", K_PAD_DOWN);
  1415.     kpinsert(&pico_kbesc, "\033C", K_PAD_RIGHT);
  1416.     kpinsert(&pico_kbesc, "\033D", K_PAD_LEFT);
  1417.  
  1418.     /*
  1419.      * DEC vt52 application keys, and some Zenith 19.
  1420.      */
  1421.     kpinsert(&pico_kbesc, "\033?r", K_PAD_DOWN);
  1422.     kpinsert(&pico_kbesc, "\033?t", K_PAD_LEFT);
  1423.     kpinsert(&pico_kbesc, "\033?v", K_PAD_RIGHT);
  1424.     kpinsert(&pico_kbesc, "\033?x", K_PAD_UP);
  1425.  
  1426.     /*
  1427.      * Sun Console sequences.
  1428.      */
  1429.     kpinsert(&pico_kbesc, "\033[1",   K_SWALLOW_TIL_Z);
  1430.     kpinsert(&pico_kbesc, "\033[215", K_SWALLOW_UP);
  1431.     kpinsert(&pico_kbesc, "\033[217", K_SWALLOW_LEFT);
  1432.     kpinsert(&pico_kbesc, "\033[219", K_SWALLOW_RIGHT);
  1433.     kpinsert(&pico_kbesc, "\033[221", K_SWALLOW_DOWN);
  1434.  
  1435.     /*
  1436.      * Kermit App Prog Cmd, gobble until ESC \ (kermit should intercept this)
  1437.      */
  1438.     kpinsert(&pico_kbesc, "\033_", K_KERMIT);
  1439.  
  1440.     /*
  1441.      * Fake a control character.
  1442.      */
  1443.     kpinsert(&pico_kbesc, "\033\033", K_DOUBLE_ESC);
  1444. }
  1445.  
  1446.  
  1447. #define    newnode()    (KBESC_T *)malloc(sizeof(KBESC_T))
  1448. /*
  1449.  * kpinsert - insert a keystroke escape sequence into the global search
  1450.  *          structure.
  1451.  */
  1452. void
  1453. kpinsert(trie, kstr, kval)
  1454.     KBESC_T **trie;
  1455.     char     *kstr;
  1456.     int       kval;
  1457. {
  1458.     register    char    *buf;
  1459.     register    KBESC_T *temp;
  1460.     register    KBESC_T *trail;
  1461.  
  1462.     if(kstr == NULL)
  1463.       return;
  1464.  
  1465.     /*
  1466.      * Don't allow escape sequences that don't start with ESC.
  1467.      */
  1468.     if(*kstr != '\033')
  1469.       return;
  1470.  
  1471.     temp = trail = *trie;
  1472.     buf = kstr;
  1473.  
  1474.     for(;;) {
  1475.     if(temp == NULL){
  1476.         temp = newnode();
  1477.         temp->value = *buf;
  1478.         temp->func = 0;
  1479.         temp->left = NULL;
  1480.         temp->down = NULL;
  1481.         if(*trie == NULL)
  1482.           *trie = temp;
  1483.         else
  1484.           trail->down = temp;
  1485.     }
  1486.     else{                /* first entry */
  1487.         while((temp != NULL) && (temp->value != *buf)){
  1488.         trail = temp;
  1489.         temp = temp->left;
  1490.         }
  1491.  
  1492.         if(temp == NULL){   /* add new val */
  1493.         temp = newnode();
  1494.         temp->value = *buf;
  1495.         temp->func = 0;
  1496.         temp->left = NULL;
  1497.         temp->down = NULL;
  1498.         trail->left = temp;
  1499.         }
  1500.     }
  1501.  
  1502.     if(*(++buf) == '\0')
  1503.       break;
  1504.     else{
  1505.         /*
  1506.          * Ignore attempt to overwrite shorter existing escape sequence.
  1507.          * That means that sequences with higher priority should be
  1508.          * set up first.
  1509.          */
  1510.         if(temp->func != 0)
  1511.           return;
  1512.  
  1513.         trail = temp;
  1514.         temp = temp->down;
  1515.     }
  1516.     }
  1517.     
  1518.     /*
  1519.      * Ignore attempt to overwrite longer sequences we are a prefix
  1520.      * of (down != NULL) and exact same sequence (func != 0).
  1521.      */
  1522.     if(temp != NULL && temp->down == NULL && temp->func == 0)
  1523.       temp->func = kval;
  1524. }
  1525.